Ritorna all'inizio


Domini funzionali e cartesiani

Un dominio è, nella pratica della semantica denotazionale, una CPO: un ordine parziale completo dotato di elemento minimo . Questo articolo dà per acquisita la teoria degli ordini, poset, catene e lub, CPO e CPO, funzioni monotone e continue, Teorema di Kleene, e si concentra su un'altra domanda: come si costruiscono i domini in modo compositivo, e perché le funzioni che vi operano risultano continue.

La motivazione è dare semantica denotazionale a un linguaggio funzionale tipato (l'esempio di riferimento è HOFL, Higher-Order Functional Language). Servono allora non un dominio, ma una famiglia intera: un dominio Dτ per ciascun tipo τ::=intτ0*τ1τ0τ1 in modo che ogni termine t:τ denoti un valore [[t]]ρDτ (dove ρ è un ambiente type-sensitive che assegna alle variabili valori del dominio giusto). Inoltre, poiché HOFL ha la ricorsione recx.t, il significato si ottiene risolvendo un'equazione ricorsiva tramite fix, e quindi ogni Dτ deve essere una CPO e ogni funzionale coinvolto deve essere continuo.

La strategia è compositiva: si fissa il dominio base Dint e si forniscono dei costruttori che, dati Dτ0 e Dτ1, producono Dτ0*τ1 e Dτ0τ1. Il requisito cruciale è che ogni costruttore preservi la struttura di CPO, e che le operazioni associate (proiezioni, applicazione, ricorsione…) siano continue.

Il dominio piatto degli interi

Il tipo base si interpreta nel dominio piatto Dint=: gli interi più un che rappresenta la non terminazione. Essendo un ordine piatto è automaticamente una CPO (ha bottom e ammette solo catene finite).

Le operazioni aritmetiche op{+,×} si sollevano al dominio piatto come estensioni strette op:×: il risultato v1mathbinopv2 vale v1mathbinopv2 quando entrambi gli argomenti sono interi (v1,v2), e vale altrimenti (cioè non appena v1= oppure v2=).

"Stretta" significa che si propaga: se un argomento diverge, diverge il risultato. Queste funzioni sono monotone e continue, automaticamente, poiché il loro dominio × ammette solo catene finite (vale il lemma "niente catene infinite monotona = continua").

Prodotto cartesiano di domini

Date due CPO D ed E, il prodotto cartesiano D×E si ordina componente per componente: (d0,e0)D×E(d1,e1)d0Dd1e0Ee1

Si verifica che D×E è ancora una CPO:

i(di,ei)=(idi,iei) È un maggiorante (ogni componente lo è) ed è il minimo dei maggioranti (se (d,e) maggiora la catena, allora d maggiora {di} ed e maggiora {ei}, da cui la disuguaglianza componente per componente).

Le proiezioni π1(d,e)=d e π2(d,e)=e sono monotone e continue. La continuità di π1, ad esempio, è immediata dalla definizione di lub di coppie: π1(i(di,ei))=π1(idi,iei)=idi=iπ1(di,ei)

Variante: prodotto smashed. Talvolta si usa il prodotto "schiacciato" DE, che identifica in un unico bottom tutte le coppie con almeno una componente indefinita. È un buon esercizio verificare che anch'esso è una CPO.

Switch lemma

Prima di affrontare lo spazio delle funzioni serve uno strumento tecnico, tanto semplice da enunciare quanto utile: lo switch lemma, che dice quando è lecito scambiare l'ordine di due lub annidati.

Lemma (switch). Sia E una CPO e {en,m}n,m una famiglia doppiamente indicizzata, monotona in entrambi gli indici: en,men,msennmm Allora ogni riga, ogni colonna e la diagonale sono catene, e i tre modi di "saturare" la matrice coincidono: nmen,m=mnen,m=kek,k

Idea della dimostrazione. Si prova che tutti questi insiemi hanno lo stesso insieme di maggioranti (per riga: ogni elemento di una riga sta sotto al lub di riga; per diagonale: ogni en,m sta sotto a ek,k con k=max{n,m}, perché nk e mk). Avendo gli stessi maggioranti, hanno lo stesso minimo dei maggioranti.

Intuitivamente: per calcolare il limite di una "matrice crescente" si può procedere per righe, per colonne o lungo la diagonale, ottenendo sempre lo stesso risultato.

Spazio delle funzioni

Date due CPO D ed E, il dominio funzionale [DE] è l'insieme delle funzioni continue da D a E, non tutte le funzioni, solo quelle continue, ordinate punto a punto: f[DE]gdD.f(d)Eg(d)

Conviene avere in mente alcuni esempi su []. Due funzioni totali distinte sono sempre inconfrontabili (ogni funzione totale è massimale): per avere fg con fg occorre che f sia indefinita () là dove g è definita, e che coincidano altrove. L'ordine [DE] misura quindi quanto una funzione "raffina" l'altra estendendone il dominio di definizione.

Anche [DE] è una CPO:

1. Ogni catena di funzioni {fn} (anche non continue) ha come lub la funzione definita punto a punto h=λd.nfn(d)cioèh(d)=nfn(d) che è un maggiorante ed è il minimo dei maggioranti (entrambe le verifiche si fanno punto a punto). 2. Se le fn sono continue, allora anche h lo è, ed è qui che interviene lo switch lemma. Data una catena {di} in D: h(idi)=nfn(idi)=nifn(di)=infn(di)=ih(di) Lo scambio centrale dei due lub è lecito perché la famiglia en,i=fn(di) è monotona in entrambi gli indici: se nm e ij allora fn(di)fn(dj)fm(dj) (per continuità/monotonia di fn e per fnfm).

Poiché il limite di una catena di funzioni continue è continuo, esso appartiene a [DE], che risulta dunque chiuso e completo. Ricordiamo infine che la composizione di funzioni continue è continua, cioè se f[DE] e g[EF] allora gf[DF].

Domini sollevati e somma disgiunta

Per completare la cassetta degli attrezzi servono altri due costruttori.

Il sollevamento (lifting) di una CPO D è D={}D. Attenzione: non è l'ordine piatto. Il lifting aggiunge un nuovo bottom strettamente sotto a una copia fedele d di D, conservandone l'ordine interno: Dxx;d1Dd2d1Dd2 È una CPO, con idi=idi. L'operatore di lifting ()*:[DE][DE] trasforma f in f* con f*()=E e f*(d)=f(d): è ben definito, monotono e continuo. Su di esso si basa la comoda notazione di de-lifting letxt.e, che estrae il valore da t (se definito) e lo assegna a x in e, propagando altrimenti E.

La somma disgiunta D+E=(DE,) affianca i due domini tenendoli separati (tramite iniezioni continue ιD,ιE); serve a interpretare i tipi unione. La costruzione dell'ordine, del bottom e delle iniezioni è un utile esercizio.

Teoremi di continuità

Verificare la continuità "a mano" di ogni funzione semantica sarebbe poco pratico. I teoremi di continuità permettono di ridurre il problema a controlli più semplici, e forniscono un compendio di operatori già noti essere continui.

Continuità sul codominio prodotto

Teorema. Sia f:DE1×E2 e poniamo gi=πif. Allora f è continua se e solo se g1 e g2 lo sono.

La direzione () segue dal fatto che le proiezioni sono continue e la composizione di funzioni continue è continua. La direzione () si calcola componente per componente, usando che f(d)=(g1(d),g2(d)) e che il lub nelle coppie è componente per componente. In pratica: una funzione a valori in un prodotto è continua esattamente quando lo sono le sue componenti.

Continuità separata sugli argomenti

Teorema. Sia f:D×EF. Definite le applicazioni parziali fd=λe.f(d,e):EFfe=λd.f(d,e):DF allora f è continua se e solo se fd è continua per ogni dD e fe è continua per ogni eE.

Questo è uno dei risultati più usati: per stabilire la continuità di una funzione a due argomenti basta controllarla un argomento alla volta. La direzione delicata è (): data una catena {(dk,ek)} in D×E, si separa il lub di coppie e si applica la continuità prima su un argomento e poi sull'altro, usando infine lo switch lemma per ricomporre il doppio lub f(k(dk,ek))=jif(di,ej)=kf(dk,ek) applicabile perché f(di,ej) è monotona in i e in j (le applicazioni parziali sono monotone).

Attenzione. Continuità (e perfino monotonia) separata va verificata con cura: una funzione può essere ben definita "come grafo" ma non monotona se "guarda" se un argomento è . Ad esempio g(x,y)=xy se x,y e g(,y)=0 non è nemmeno monotona, perché g(,)=0not valori prodotti quando gli argomenti si raffinano.

Operatori fondamentali

I teoremi precedenti permettono di dimostrare che i costituenti della semantica denotazionale sono continui:

In definitiva, i costruttori (prodotto, spazio funzionale, lifting, somma) sono chiusi rispetto alla struttura di CPO, e gli operatori fondamentali sono continui: abbiamo così un linguaggio completo per costruire, in modo compositivo, i domini e le funzioni semantiche di un linguaggio funzionale di ordine superiore.

Articoli correlati